Writing a 2D effect in Java

By Bad Sector / Nasty Bugs

One day I decided to remake my web page which had not been updated for 2 years. While creating a (not so good) page I came with the idea of adding a little effect to the top left area of the screen. I actually wanted to have a very small 3D "B" rotating. At the beginning I tried to implement my idea with JavaScript using Vector Balls, a method I had successfully programmed a couple of months ago. However, even though it worked, I didn't like the result; it wasn't really 3D. So I decided to make a simple rasterizer that drew triangles. Again I tried to do that in JavaScript using a table as a framebuffer. However, it was very slow as it needed about 2 seconds to draw a single triangle. After these attempts, I decided to switch the programming language to Java...

However, I had never used Java before (ok, almost never) and I didn't know what to do. I had an ancient version of the JDK for Java 1 so I installed it along with its docs (Sun distributes the docs and the development kit separately). I opened Notepad and after seeing some examples and browsing the documentation, I started coding. Yet nothing was working. At the beginning I had problems because of the misuse of the language (I'm not familiar with Java). After resolving them (which was easy), I occured some exception errors (NullException or something like that). I didn't know 'why' so I rewrote the whole code. Anyway, I don't want to retell all these thing... Let me just conclude: It didn't work. The docs were very badly written and I had to use 9384729 objects and make half of the classes just to do a single thing. And, anyway, the results didn't match my intentions.

Then I realized that I ought to get the latest Java SDK (1.4.2 Beta). So that's what I did. First I downloaded the SDK itself and two days later the docs (I don't have an Internet connection at my home so I have to go to cyber cafes). And finally after some browses in the docs and many mistakes, I realized how it's done! So this is what I'm going to tell you.

In this very small tutorial that I have written on a day with the same date as the one on which I saw the light, since I didn't want to miss Hugi's deadline, I will explain how to create a small .java file that will produce two .class files which you'll use to make a .jar file in order to put a small effect into a .html file. Everything is included in the BxFX.zip that comes with the Hugi bonus pack (I suppose). And here we go.

0. System requirements

You'll need the following:

1. A Web browser. I recommend Mozilla - http://www.mozilla.org/

2. Java 2 1.4.2 (or newer) SDK Standard Edition. Get it at http://java.sun.com/ (it includes JRE)

3. Java 2 1.4.2 (or newer) Documentation. Get it at the same place as Java SDK

4. A good text editor (personally I prefer Notepad from Windows 2000)

5. Patience

1. Create the BxFX applet class

Make a new text file and write the following code:

import java.applet.Applet;
import java.awt.Graphics;
public class BxFX extends Applet
{
	public void init()
	{
	}
	public void paint(Graphics g)
	{
	}
	public String getAppletInfo()
	{
		return "BxFX Applet for Bad Sector's "
		       "homepage by Bad Sector :-)";
	}
}

Save the above code in the file BxFX.java. After that declare a BufferedImage object (don't forget to put a import java.awt.image.BufferedImage; line in the imports at the top of the code) in the class, like:

public class BxFX extends Applet
{
	BufferedImage	TheImage;

and create it in the init() function:

TheImage = (BufferedImage) createImage(160, 120);

Note: our applet will always be 160x120. If you want to make a control of variable size, use the getSize() function (for more information take a look at Java's SDK). Then in the paint function put the following line of code, in order to make the applet draw the image itself when asked to do so:

g.drawImage(TheImage, 0, 0, null);

Finally put the following line of code in the init function to make the background black (by default it is white):

setBackground(new Color(0, 0, 0, 0));

2. Create the DrawBxFX class

The DrawBxFX class is the class that will calculate the next frame and draw it on the BxFX applet. It is derived from the TimerTask class and will be used with a Timer class, which allows us to execute a TimerTask class at a fixed rate (for example every 50 milliseconds). The code for this class is the following:

class DrawBxFX extends TimerTask
{
	Applet		FXApplet;
	int		Pixels[];
	BufferedImage	TheImage;
	DrawBxFX(Applet TargetApplet, BufferedImage TargetImage)
	{
		Pixels = new int[160*120];
		FXApplet = TargetApplet;
		TheImage = TargetImage;	
	}
	public void run()
	{
		Graphics g;
                // Produce an image in the Pixels array here
                // Copy the Pixels array in the Image and draw
                // the Image on the applet
        TheImage.setRGB(0, 0, 160, 120, Pixels, 0, 160);
        g = FXApplet.getGraphics();
        g.drawImage(TheImage, 0, 0, null);
	}
}

I suppose that it's very straightforward what this class does. When it is initialized by the DrawBxFX constructor, two arguments are passed: TargetApplet, which is the Applet object that DrawBxFX will use (we will always pass this to this argument) and TargetImage, which is the BufferedImage object where Pixels will be drawn. The constructor also allocates space for 160*120 (actually Width*Height) pixels. Then in the run() function, which will be called by Timer, a frame is being generated (actually it doesn't, but you'll write the code that does that) in the Pixels array, then the array is being copied in the image and finally the image is drawn on the applet by getting a Graphics object (the g) for the applet and drawing the image on it (note: the SDK says that getGraphics creates an object. I don't know if this is true or not; however, there are no memory problems with the applet, since - according to Java Console - it doesn't eat memory for every frame, which is something I suspected at first).

3. Back to BxFX class in order to set up a timer

Now we have a TimerTask class (I mean the DrawBxFX class), so our last step is to set up a Timer object that will call this task every 50 milliseconds. To do that, first declare a Timer object in BxFX like:

public class BxFX extends Applet
{
	BufferedImage	TheImage;
	Timer		aTimer;

then in the init() function create the aTimer, like:

aTimer = new Timer();

and make it call a DrawBxFX object every 50 milliseconds:

aTimer.scheduleAtFixedRate(new DrawBxFX(this, TheImage), 0, 50);

and... that's it. Compile it and you'll have two files: BxFX.class and DrawBxFX.class. You can now use them in your HTML.

4. Making a .jar file from the .class files

A simple task, since those .jar files are simply .zip files. Just use your favourite ZIPper (like WinZip or WinRAR) to compress all the files you use (.class files and others like images and sounds) and change the extension from .zip to .jar.

[Editor's note: That's quite interesting because there also used to be a file archiver called JAR. It was the official sequel to ARJ, invented by the original creator of ARJ, Robert Jungk. Back in 1997 it was a big hit because it managed to produce an even better compression ratio than RAR. The compression algorithm was heavily dependent on memory; the more free memory you had, the better it compressed the file. - I wonder why JAR is virtually unknown these days. //Adok]

5. Using BxFX in an HTML file

To use BxFX in an HTML file, just write the code below:

<applet code="BxFX.class"
	archive="BxFX.jar"
	width="160"
	height="120">
</applet>

The code parameter defines the main class file, the archive parameter defines the .jar file and the width and height the size of the rectangular area that the applet will use on the page. Note that if you change these values here, you must change them in the source code as well.

6. Conclusion

I don't know whether and I won't claim that that the above code is the best way for creating a 2D effect. As mentioned, I have very little experience in Java and if you know a better (= faster) method, I would like to learn it via e-mail (see below). However, I decided to write this article because it took me a lot of time to figure out how to do it (don't get fooled by the first paragraph and think that when I got the latest SDK I learned it all; when I had the 1.1.8 version of JDK I spent hours searching the docs and now with the new docs I knew where to look) and I thought that others might want to do the same thing as me and don't know how.

Unfortunately, the documentation of the Java SDK is very badly written (I think that is has been generated on the basis of comments - a bad new fashion) and doesn't contain examples except for very general cases and only in some classes. Personally I believe that a good documentation for an API or a language should include at least one example for every feature, function, class, etc.

Anyway. Along with HUGI you'll find a .zip file (BxFX.zip) in the bonus pack that contains the discussed class with extra code to implement a bouncing pixel and a HTML page that uses it in .jar form (including the .jar).

Bad Sector / Nasty Bugs